﻿Imports System.Security.Cryptography
Imports System.IO
Imports Microsoft.Win32
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.EditorInput
'Imports Autodesk.AutoCAD.Interop
Public Module CLDS_Static_Utils
    Public Function CLDS_DrawingSaved() As Boolean
        Dim dbmod As Object = Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("DBMOD")
        Dim dwgtitled As Object = Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("DWGTITLED")

        '' Check the value of DBMOD, if 0 then the drawing has not been changed
        If (System.Convert.ToInt16(dwgtitled) = 0) Or Not (System.Convert.ToInt16(dbmod) = 0) Then
            Return False
        Else
            Return True
        End If
    End Function
    Public Function CLDS_Encrypt(ByVal p_str As String) As String
        Dim IV() As Byte = {&H12, &H34, &H56, &H78, &H90, &HAB, &HCD, &HEF}
        If p_str Is Nothing Then
            Return ""
        End If
        If p_str = "" Then
            Return ""
        End If
        Try
            Dim bykey() As Byte = System.Text.Encoding.UTF8.GetBytes(Left("CmPiCrOoLsOk", 8))
            Dim InputByteArray() As Byte = System.Text.Encoding.UTF8.GetBytes(p_str)
            Dim des As New DESCryptoServiceProvider
            Dim ms As New MemoryStream
            Dim cs As New CryptoStream(ms, des.CreateEncryptor(bykey, IV), CryptoStreamMode.Write)
            cs.Write(InputByteArray, 0, InputByteArray.Length)
            cs.FlushFinalBlock()
            CLDS_Encrypt = Convert.ToBase64String(ms.ToArray())
        Catch ex As Exception
            MsgBox(ex.Message, MsgBoxStyle.Critical, "CMPIC Encryption")
            CLDS_Encrypt = ""
        End Try
    End Function
    Public Function CLDS_Decrypt(ByVal p_str As String) As String
        Dim IV() As Byte = {&H12, &H34, &H56, &H78, &H90, &HAB, &HCD, &HEF}
        Dim inputByteArray(p_str.Length) As Byte
        Try
            Dim byKey() As Byte = System.Text.Encoding.UTF8.GetBytes(Left("CmPiCrOoLsOk", 8))
            Dim des As New DESCryptoServiceProvider
            inputByteArray = Convert.FromBase64String(p_str)
            Dim ms As New MemoryStream
            Dim cs As New CryptoStream(ms, des.CreateDecryptor(byKey, IV), CryptoStreamMode.Write)
            cs.Write(inputByteArray, 0, inputByteArray.Length)
            cs.FlushFinalBlock()
            Dim encoding As System.Text.Encoding = System.Text.Encoding.UTF8
            CLDS_Decrypt = encoding.GetString(ms.ToArray())
        Catch ex As Exception
            MsgBox(ex.Message, MsgBoxStyle.Critical, "CMPIC Decryption")
            CLDS_Decrypt = ""
        End Try
    End Function
    Public Function CLDS_Source_From_File(ByVal p_file As String) As String
        If p_file = "" Then
            Return ""
        End If
        Dim s As String = p_file
        Dim r As String = """'&?!$+@~#"
        For i As Integer = 1 To Len(r)
            s = Replace$(s, Mid$(r, i, 1), "_")
        Next
        If Len(s) > 200 Then
            s = Mid$(s, 1, 200)
        End If
        Return s
    End Function
    Public Function CLDS_Key_Value(ByVal p_key As String) As String
        'Dim k_key As String = p_key
        Dim b_key As Byte() = System.Text.Encoding.UTF8.GetBytes(p_key)
        Dim k_key As String = Convert.ToBase64String(b_key)
        k_key = Replace$(k_key, "=", "$")
        'k_key = Replace$(Replace$(Replace$(k_key, "/", "_"), " ", "_"), "*", "$")
        CLDS_Key_Value = k_key
    End Function
    Public Function CLDS_Node_Key(ByVal p_id As String) As String
        Return "NODE_" & CLDS_Key_Value(p_id)
    End Function
    Public Function CLDS_Segment_Key(ByVal p_n1 As String, ByVal p_n2 As String) As String
        Return "SEG_" & CLDS_Key_Value(p_n1) & "__" & CLDS_Key_Value(p_n2)
    End Function
    Public Function CLDS_IsInteger(ByVal p_val As String) As Integer
        Dim r As Double
        Dim t As Boolean
        t = Double.TryParse(p_val, System.Globalization.NumberStyles.Integer, _
                                System.Globalization.CultureInfo.CurrentCulture, r)
        If t Then
            CLDS_IsInteger = r
        Else
            CLDS_IsInteger = -1
        End If
    End Function
    Public Function CLDS_ProjectPath(ByVal pn As String) As String
        CLDS_ProjectPath = ""
        If pn = "" Then
            Exit Function
        End If
        Dim acadKey As RegistryKey
        Dim keyName As String = "Software\Autodesk"
        acadKey = Registry.CurrentUser.OpenSubKey(keyName, False)
        If acadKey Is Nothing Then
            Exit Function
        End If
        Dim acadVal As String
        acadVal = acadKey.GetValue("CurProd", "")   ' AutoCAD
        acadKey.Close()
        If acadVal = "" Then
            Exit Function
        End If
        keyName = keyName & "\" & acadVal
        acadKey = Registry.CurrentUser.OpenSubKey(keyName, False)
        If acadKey Is Nothing Then
            Exit Function
        End If
        acadVal = acadKey.GetValue("CurVer", "")    ' 19.0
        acadKey.Close()
        If acadVal = "" Then
            Exit Function
        End If
        keyName = keyName & "\" & acadVal
        acadKey = Registry.CurrentUser.OpenSubKey(keyName, False)
        If acadKey Is Nothing Then
            Exit Function
        End If
        acadVal = acadKey.GetValue("CurVer", "")    ' ACAD_B001:409
        acadKey.Close()
        If acadVal = "" Then
            Exit Function
        End If
        keyName = keyName & "\" & acadVal & "\" & "Profiles"
        acadKey = Registry.CurrentUser.OpenSubKey(keyName, False)
        If acadKey Is Nothing Then
            Exit Function
        End If
        acadVal = acadKey.GetValue("", "")    ' ShipConstructor 2013
        acadKey.Close()
        If acadVal = "" Then
            Exit Function
        End If
        keyName = keyName & "\" & acadVal & "\" & "Project Settings" & "\" & pn
        acadKey = Registry.CurrentUser.OpenSubKey(keyName, False)
        If acadKey Is Nothing Then
            Exit Function
        End If
        acadVal = acadKey.GetValue("RefSearchPath", "")    ' Project path
        acadKey.Close()
        If acadVal = "" Then
            Exit Function
        End If
        CLDS_ProjectPath = acadVal
    End Function
    Public Function CLDS_ProjectNames() As String
        Dim pn As String = ""
        Dim acadKey As RegistryKey
        Dim keyName As String = "Software\Autodesk"
        acadKey = Registry.CurrentUser.OpenSubKey(keyName, False)
        If acadKey Is Nothing Then
            Return pn
        End If
        Dim acadVal As String
        acadVal = acadKey.GetValue("CurProd", "")   ' AutoCAD
        acadKey.Close()
        If acadVal = "" Then
            Return pn
        End If
        keyName = keyName & "\" & acadVal
        acadKey = Registry.CurrentUser.OpenSubKey(keyName, False)
        If acadKey Is Nothing Then
            Return pn
        End If
        acadVal = acadKey.GetValue("CurVer", "")    ' 19.0
        acadKey.Close()
        If acadVal = "" Then
            Return pn
        End If
        keyName = keyName & "\" & acadVal
        acadKey = Registry.CurrentUser.OpenSubKey(keyName, False)
        If acadKey Is Nothing Then
            Return pn
        End If
        acadVal = acadKey.GetValue("CurVer", "")    ' ACAD_B001:409
        acadKey.Close()
        If acadVal = "" Then
            Return pn
        End If
        keyName = keyName & "\" & acadVal & "\" & "Profiles"
        acadKey = Registry.CurrentUser.OpenSubKey(keyName, False)
        If acadKey Is Nothing Then
            Return pn
        End If
        acadVal = acadKey.GetValue("", "")    ' ShipConstructor 2013
        acadKey.Close()
        If acadVal = "" Then
            Return pn
        End If
        keyName = keyName & "\" & acadVal & "\" & "Project Settings" & "\"
        Dim p() As String = Registry.CurrentUser.OpenSubKey(keyName, False).GetSubKeyNames
        For Each x In p
            If pn <> "" Then
                pn = pn & ","
            End If
            pn = pn & x
        Next
        Return pn
    End Function
    Public Function CLDS_FindFile(ByVal p_file As String) As String
        Try
            Dim XFN As String = HostApplicationServices.Current.FindFile(p_file, Application.DocumentManager.MdiActiveDocument.Database, FindFileHint.XRefDrawing)
            Return XFN
        Catch xex As Exception
        End Try
        Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
        Dim pn As String = Application.GetSystemVariable("PROJECTNAME")
        If pn = "" Then
            Return ""
        End If
        '        Dim ap As AcadPreferences = Application.Preferences
        '        Dim pp As String = ap.Files.GetProjectFilePath(pn)
        Dim pp As String = CLDS_ProjectPath(pn)
        If pp = "" Then
            Return ""
        End If
        Dim p() As String = Split(pp, ";")
        For i As Integer = 0 To UBound(p)
            Dim f As String = p(i) & "\" & p_file
            If File.Exists(f) Then
                Return f
            End If
        Next
        Return ""
    End Function
    Public Function CLDS_TrimString(ByVal p_s As String) As String
        Dim o_s As String = Trim(p_s)
        Dim l As Integer = Len(o_s)
        For i As Integer = 1 To l
            If o_s = "" Then
                Exit For
            End If
            If Asc(Left(o_s, 1)) = 13 Or Asc(Left(o_s, 1)) = 10 Then
                o_s = Mid$(o_s, 2)
            Else
                Exit For
            End If
        Next
        l = Len(o_s)
        For i As Integer = l To 1 Step -1
            If o_s = "" Then
                Exit For
            End If
            If Asc(Mid$(o_s, i)) = 13 Or Asc(Mid$(o_s, i)) = 10 Then
                o_s = Mid$(o_s, 1, i - 1)
            Else
                Exit For
            End If
        Next
        Return o_s
    End Function
    Public Function CLDS_DisplayString(ByVal p_s As String) As String
        Return Replace$(p_s, Chr(10), Environment.NewLine)
    End Function
    Public Function CLDS_ExtractError(ByVal p_full As String) As String
        Dim e1 As Integer = InStr(p_full, "ERROR: [", CompareMethod.Text)
        If e1 = 0 Then
            Return p_full
        End If
        Dim s As String = Mid$(p_full, e1)
        Dim e2 As Integer = InStr(s, "ORA-", CompareMethod.Text)
        If e2 > 0 Then
            s = Mid$(s, 1, e2 - 1)
        End If
        s = Trim(s)
        Return s
    End Function
    Public Sub CLDS_WriteMessage(ByVal p_ed As Autodesk.AutoCAD.EditorInput.Editor, ByVal p_mssg As String)
        If p_mssg = "" Then
            Exit Sub
        End If
        p_ed.WriteMessage(vbCrLf & p_mssg & vbCrLf & "Command: ")
    End Sub
    Public Sub Zoom(ByVal pMin As Point3d, ByVal pMax As Point3d, _
                    ByVal pCenter As Point3d, ByVal dFactor As Double)
        '' Get the current document and database
        Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
        Dim acCurDb As Database = acDoc.Database

        Dim nCurVport As Integer = System.Convert.ToInt32(Application.GetSystemVariable("CVPORT"))

        '' Get the extents of the current space when no points 
        '' or only a center point is provided
        '' Check to see if Model space is current
        If acCurDb.TileMode = True Then
            If pMin.Equals(New Point3d()) = True And _
                pMax.Equals(New Point3d()) = True Then

                pMin = acCurDb.Extmin
                pMax = acCurDb.Extmax
            End If
        Else
            '' Check to see if Paper space is current
            If nCurVport = 1 Then
                If pMin.Equals(New Point3d()) = True And _
                   pMax.Equals(New Point3d()) = True Then

                    pMin = acCurDb.Pextmin
                    pMax = acCurDb.Pextmax
                End If
            Else
                '' Get the extents of Model space
                If pMin.Equals(New Point3d()) = True And _
                   pMax.Equals(New Point3d()) = True Then

                    pMin = acCurDb.Extmin
                    pMax = acCurDb.Extmax
                End If
            End If
        End If

        '' Start a transaction
        Using acTrans As Transaction = acCurDb.TransactionManager.StartTransaction()
            '' Get the current view
            Using acView As ViewTableRecord = acDoc.Editor.GetCurrentView()
                Dim eExtents As Extents3d

                '' Translate WCS coordinates to DCS
                Dim matWCS2DCS As Matrix3d
                matWCS2DCS = Matrix3d.PlaneToWorld(acView.ViewDirection)
                matWCS2DCS = Matrix3d.Displacement(acView.Target - Point3d.Origin) * matWCS2DCS
                matWCS2DCS = Matrix3d.Rotation(-acView.ViewTwist, _
                                               acView.ViewDirection, _
                                               acView.Target) * matWCS2DCS

                '' If a center point is specified, define the 
                '' min and max point of the extents
                '' for Center and Scale modes
                If pCenter.DistanceTo(Point3d.Origin) <> 0 Then
                    pMin = New Point3d(pCenter.X - (acView.Width / 2), _
                                       pCenter.Y - (acView.Height / 2), 0)

                    pMax = New Point3d((acView.Width / 2) + pCenter.X, _
                                       (acView.Height / 2) + pCenter.Y, 0)
                End If

                '' Create an extents object using a line
                Using acLine As Line = New Line(pMin, pMax)
                    eExtents = New Extents3d(acLine.Bounds.Value.MinPoint, _
                                             acLine.Bounds.Value.MaxPoint)
                End Using

                '' Calculate the ratio between the width and height of the current view
                Dim dViewRatio As Double
                dViewRatio = (acView.Width / acView.Height)

                '' Tranform the extents of the view
                matWCS2DCS = matWCS2DCS.Inverse()
                eExtents.TransformBy(matWCS2DCS)

                Dim dWidth As Double
                Dim dHeight As Double
                Dim pNewCentPt As Point2d

                '' Check to see if a center point was provided (Center and Scale modes)
                If pCenter.DistanceTo(Point3d.Origin) <> 0 Then
                    dWidth = acView.Width
                    dHeight = acView.Height

                    If dFactor = 0 Then
                        pCenter = pCenter.TransformBy(matWCS2DCS)
                    End If

                    pNewCentPt = New Point2d(pCenter.X, pCenter.Y)
                Else '' Working in Window, Extents and Limits mode
                    '' Calculate the new width and height of the current view
                    dWidth = eExtents.MaxPoint.X - eExtents.MinPoint.X
                    dHeight = eExtents.MaxPoint.Y - eExtents.MinPoint.Y

                    '' Get the center of the view
                    pNewCentPt = New Point2d(((eExtents.MaxPoint.X + eExtents.MinPoint.X) * 0.5), _
                                             ((eExtents.MaxPoint.Y + eExtents.MinPoint.Y) * 0.5))
                End If

                '' Check to see if the new width fits in current window
                If dWidth > (dHeight * dViewRatio) Then dHeight = dWidth / dViewRatio

                '' Resize and scale the view
                If dFactor <> 0 Then
                    acView.Height = dHeight * dFactor
                    acView.Width = dWidth * dFactor
                End If

                '' Set the center of the view
                acView.CenterPoint = pNewCentPt

                '' Set the current view
                acDoc.Editor.SetCurrentView(acView)
            End Using

            '' Commit the changes
            acTrans.Commit()
        End Using
    End Sub
    Public Sub ZoomScale()
        '' Get the current document
        Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument

        '' Get the current view
        Using acView As ViewTableRecord = acDoc.Editor.GetCurrentView()
            '' Get the center of the current view
            Dim pCenter As Point3d = New Point3d(acView.CenterPoint.X, _
                                                 acView.CenterPoint.Y, 0)

            '' Set the scale factor to use
            Dim dScale As Double = 0.5

            '' Scale the view using the center of the current view
            Zoom(New Point3d(), New Point3d(), pCenter, 1 / dScale)
        End Using
    End Sub
    Public Sub ZoomWin1(ByVal ed As Editor, ByVal min As Point3d, ByVal max As Point3d)
        Dim cv As ViewTableRecord = ed.GetCurrentView
        Dim cp As Point3d = min + ((max - min) / 2.0)
        'ed.GetCurrentView.Target = cp
        Dim nv As New ViewTableRecord
        nv.Target = cp
        nv.CenterPoint = Point2d.Origin
        nv.Height = cv.Height
        nv.Width = cv.Width
        nv.ViewDirection = cv.ViewDirection
        ed.SetCurrentView(nv)
    End Sub
    Public Sub ZoomWin3(ByVal ed As Autodesk.AutoCAD.EditorInput.Editor, ByVal min As Point3d, ByVal max As Point3d)
        Dim lower As String = min.ToString().Substring(1, min.ToString.Length - 2)
        Dim upper As String = max.ToString().Substring(1, max.ToString.Length - 2)
        Dim cmd As String = "_.ZOOM W " & lower & " " & upper & " "
        ed.Document.SendStringToExecute(cmd, True, False, True)
    End Sub
    Public Sub ZoomWin4(ByVal ed As Autodesk.AutoCAD.EditorInput.Editor, ByVal cp As Point3d)
        Dim c As String = cp.ToString().Substring(1, cp.ToString.Length - 2)
        Dim cmd As String = "_.ZOOM C " & c & " " & vbCr
        ed.Document.SendStringToExecute(cmd, True, False, True)
    End Sub
    Public Sub ZoomToObject(ByVal zTrans As Transaction, ByVal p_obj As ObjectId)
        Dim doc As Document
        Dim ed As Editor
        doc = Application.DocumentManager.MdiActiveDocument
        ed = doc.Editor
        Dim ent As Entity = DirectCast(zTrans.GetObject(p_obj, OpenMode.ForRead), Entity)
        Dim ext As Extents3d = ent.GeometricExtents
        ext.TransformBy(ed.CurrentUserCoordinateSystem.Inverse)
        Dim cp As Point3d = ext.MinPoint + ((ext.MaxPoint - ext.MinPoint) / 2.0)
        Zoom(New Point3d, New Point3d, cp, 0)
    End Sub
    Public Sub ZoomToEntity(ByVal p_ed As Editor, ByVal p_ent As Entity)
        Dim ext As Extents3d = p_ent.GeometricExtents
        ext.TransformBy(p_ed.CurrentUserCoordinateSystem.Inverse)
        Dim cp As Point3d = ext.MinPoint + ((ext.MaxPoint - ext.MinPoint) / 2.0)
        Zoom(New Point3d, New Point3d, cp, 0)
    End Sub
End Module
